#include "sqlconnectionpool.h"

#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QFileInfo>
#include <QDir>
//配置文件头文件
#include <QSettings>

//----------初始化静态变量----------//
QMutex SqlConnectionPool::mutex;
QWaitCondition SqlConnectionPool::waitConnection;
SqlConnectionPool* SqlConnectionPool::instance;
SqlConnectionPool::SqlConnectionPool()
{
    // 创建数据库连接的这些信息在实际开发的时都需要通过读取配置文件得到//文件存在则打开，不存在则创建
        hostName = "124.70.48.165";
        databaseName = "maodb";
        username = "root";
        password = "mao123456.";
        databaseType ="QODBC";
}

QSqlDatabase SqlConnectionPool::createConnection(const QString &connectionName)
{
    //当连接已经创建过，复用他
    if(QSqlDatabase::contains(connectionName))
    {
        qDebug() << "路径存在，复用！";

        QSqlDatabase db = QSqlDatabase::database(connectionName);
        if(testOnBorrow)
        {
            //返回连接前访问数据库，如果连接断开，重新建立连接
            qDebug() << "Test connection on borrow, execute:" << testOnBorrowSql << ", for" << connectionName;
            QSqlQuery query(testOnBorrowSql,db);
            if(query.lastError().type() != QSqlError::NoError && !db.open())
            {
                qDebug() << "Open datatabase error:" << db.lastError().text();
                return QSqlDatabase();
            }
        }
        return db;
    }
    // 创建一个新的连接,首先需要判断数据库路径是否存在

    //①判断数据库路径是否存在
    if( !isDirOrFileExits(databasePath) )
    {
        qDebug()<<databasePath<<"路径不存在!创建";
        createSqlitePath(databasePath);
    }
    //②初始化数据库连接
    QSqlDatabase db = QSqlDatabase::addDatabase(databaseType, connectionName);
    db.setHostName(hostName);
    //③获取数据库名，打开数据库
    db.setDatabaseName(databaseName);
    if(username != NULL && password != NULL)
    {
        db.setUserName(username);
        db.setPassword(password);
    }
    if (!db.open()) {
        qDebug() << "Open datatabase error:" << db.lastError().text();
        return QSqlDatabase();
    }

    return db;
}
bool SqlConnectionPool::isDirOrFileExits(QString dbName)
{
    QFileInfo fileinfo(dbName);
    return fileinfo.exists();
}

bool SqlConnectionPool::createSqlitePath(QString path)
{
    QDir parameterDir;
    return parameterDir.mkpath(path);
}

void SqlConnectionPool::release()
{
    QMutexLocker locker(&mutex);
    delete instance;
    instance = NULL;
}

QSqlDatabase SqlConnectionPool::openConnection()
{
    SqlConnectionPool& pool = SqlConnectionPool::getInstance();//变量初始化
    QString connectionName;

    QMutexLocker locker(&mutex);
    //已经创建的连接数
    int connectionCount = pool.unusedConnectionNames.size()+pool.usedConnectionNames.size();
    //如果连接已经用完，等待waitInterval毫秒看看是否有可用的连接，最长等待maxWaitTime毫秒
/*
如果没有可复用连接 pool.unusedConnectionNames.size() == 0 且已经创建的连接数达到最大，则等待，
等待期间有连接被释放回连接池就复用这个连接，如果超时都没有可用连接，则返回一个无效的连接 QSqlDatabase()。
*/

    for(int i=0;i<pool.maxWaitTime &&
        pool.unusedConnectionNames.size()==0 &&
        connectionCount == pool.maxConnectionCount;i+=pool.waitInterval)
    {
        waitConnection.wait(&mutex,pool.waitInterval);//等待
        connectionCount = pool.unusedConnectionNames.size()+pool.usedConnectionNames.size();
        //qDebug()<<"no connection to use,wait ...";
    }
    if(pool.unusedConnectionNames.size()>0)
    {
        //有已经回收的连接，复用他们
        connectionName = pool.unusedConnectionNames.dequeue();//出队
        qDebug()<<"have old connections,use them";
    }else if( connectionCount < pool.maxConnectionCount )
    {
        //还有空余，创建新的连接
        connectionName = QString("Connection-%1").arg(connectionCount + 1);
    }else
    {
        //已经达到最大连接数
        qDebug()<<"Maximum number of connections reached!!!";
        return QSqlDatabase();
    }

    //创建连接
    QSqlDatabase db = pool.createConnection(connectionName);
    //有效的连接才放入 usedConnectionNames
    if(db.isOpen())
    {
        pool.usedConnectionNames.enqueue(connectionName);
    }
    return db;
}

void SqlConnectionPool::closeConnection(QSqlDatabase connection)
{
    SqlConnectionPool& pool = SqlConnectionPool::getInstance();//变量初始化
    QString connectionName = connection.connectionName();//获取数据库连接名儿
    if(pool.usedConnectionNames.contains(connectionName))//如果是我们创建的，放入unused
    {
        QMutexLocker locker(&mutex);
        pool.usedConnectionNames.removeOne(connectionName);
        pool.unusedConnectionNames.enqueue(connectionName);
        waitConnection.wakeOne();//唤醒一个等待的线程
    }
}

SqlConnectionPool::~SqlConnectionPool()
{
    // 销毁连接池的时候删除所有的连接
    foreach(QString connectionName, usedConnectionNames) {//循环遍历
        QSqlDatabase::removeDatabase(connectionName);
    }

    foreach(QString connectionName, unusedConnectionNames) {
        QSqlDatabase::removeDatabase(connectionName);
    }
}

SqlConnectionPool &SqlConnectionPool::getInstance()
{
    if(NULL == instance)
    {
        QMutexLocker locker(&mutex);
        if(NULL == instance)
        {
            instance = new SqlConnectionPool();//sqlconnectionpool静态变量初始化
        }
    }
    return *instance;
}
